#pragma once

#include <iostream>
#include <string>

class BaseComponent;
class Mediator
{
public:
    virtual void notify(BaseComponent *sender, std::string event) const = 0;
};

class BaseComponent
{
public:
    BaseComponent(Mediator *mediator = nullptr)
    {
        this->m_mediator = mediator;
    }

public:
    void setMediator(Mediator *mediator)
    {
        this->m_mediator = mediator;
    }

protected:
    Mediator *m_mediator;
};

class Component1 : public BaseComponent
{
public:
    void todoA()
    {
        std::cout << "Component 1 does A." << std::endl;
        this->m_mediator->notify(this, "A");
    }

    void todoB()
    {
        std::cout << "Component 1 does B." << std::endl;
        this->m_mediator->notify(this, "B");
    }
};

class Component2 : public BaseComponent
{
public:
    void todoC()
    {
        std::cout << "Component 2 does C." << std::endl;
        this->m_mediator->notify(this, "C");
    }

    void todoD()
    {
        std::cout << "Component 2 does D." << std::endl;
        this->m_mediator->notify(this, "D");
    }
};

class ConcreteMediator : public Mediator
{
public:
    ConcreteMediator(Component1 *c1, Component2 *c2) : m_component1(c1), m_component2(c2)
    {
        this->m_component1->setMediator(this);
        this->m_component2->setMediator(this);
    }

public:
    void notify(BaseComponent *sender, std::string event) const override
    {
        if (event == "A") {
            std::cout << "Mediator reacts on A and triggers following operations:" << std::endl;
            this->m_component2->todoC();
        }
        if (event == "D") {
            std::cout << "Mediator reacts on D and triggers following operations:" << std::endl;
            this->m_component1->todoB();
            this->m_component2->todoC();
        }
    }

private:
    Component1 *m_component1;
    Component2 *m_component2;
};
